
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ipcfork.h"

#if defined(WIN32) || defined(WIN64) || defined(WINCE) || defined(_MSC_VER)
/* ---------- Windows begin ---------- */
#include "windows.h"
#include "process.h"

int32_t ipcfork_system(const char* filePath, char* param, int32_t isHideWindwos)
{
	PROCESS_INFORMATION pi; /* 必备参数设置结束 */
	STARTUPINFO si;
	memset(&si, 0, sizeof(STARTUPINFO)); /* 初始化si在内存块中的值 */
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESHOWWINDOW; /* 指定wShowWindow成员有效 */
	si.wShowWindow = isHideWindwos ? SW_HIDE : SW_SHOW; /* 隐藏窗口 */

	if (!CreateProcess(filePath,
		param,
		NULL, 
		NULL, 
		FALSE, 
		NORMAL_PRIORITY_CLASS,
		NULL, 
		NULL, 
		&si, 
		&pi))
	{
		printf("CreateProcess failed, errorcode=%d: %s %s", GetLastError(), filePath, param);
		return -1;
	}
	printf("CreateProcess pid/%d: %s %s", pi.dwProcessId, filePath, param);

	/* 不使用的句柄关掉 */
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
    return 0;
}

int32_t ipcfork_getProcessPid()
{
    return GetCurrentProcessId();
}

void ipcfork_killProcess(int32_t pid)
{
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
    if (hProcess == NULL) {
        return;
    }
    TerminateProcess(hProcess, 0);
    CloseHandle(hProcess);
}

int32_t ipcfork_pathOfLibrary(char* buff, int32_t buffSize, const char* libraryName, const char* appendString)
{
    GetModuleFileName(GetModuleHandle(libraryName), buff, buffSize);
    /* 只要路径不要文件名 */
    for (int32_t i = strlen(buff) - 1; i > 0; i--)
    {
        if (buff[i] == '/' || buff[i] == '\\')
        {
            buff[++i] = '\0';
            break;
        }
    }
    /* 追加内容 */
    if (appendString)
    {
        int32_t len = strlen(buff);
        snprintf(&buff[len], buffSize - len, "%s", appendString);
    }
    return 0;
}

#include "tlhelp32.h"
int32_t ipcfork_checkProcess(int32_t pid)
{
	HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (INVALID_HANDLE_VALUE == hSnapshot) {
		return -1;
	}
	PROCESSENTRY32 pe = { sizeof(pe) };
	for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe))
    {
		if (pe.th32ProcessID == pid) {
			return 0;
		}
	}
	CloseHandle(hSnapshot);
	return -1;
}

/* ---------- Windows end ---------- */
#else
/* ---------- Linux begin ---------- */
#include <unistd.h>
#include <signal.h>

int32_t ipcfork_create(int32_t(*process_main)(const char*), char* param)
{
    pid_t pid = fork();
    if (pid == 0)
    {
        int32_t ret = process_main(param);
        exit(ret);
    }
    else
    {
        printf("ipcfork_create: pid/%d \r\n", pid);
    }
    return pid;
}

int32_t ipcfork_system(const char* filePath, char* param)
{
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s %s &", filePath, param);
    printf("ipcfork_system: %s \r\n", cmd);
    system(cmd);
	return 0;
}

int32_t ipcfork_getProcessPid()
{
    return getpid();
}

void ipcfork_killProcess(int32_t pid)
{
    kill(pid, SIGKILL);
}

int32_t ipcfork_pathOfLibrary(char* buff, int32_t buffSize, const char* libraryName, const char* appendString)
{
    int32_t ret = -1;
    /* 从当前进程依赖库中获得 libraryName 所在路径 */
    do
    {
        FILE *fp = fopen((const char *)"/proc/self/maps", "r");
        if (!fp) {
            break;
        }
        char line[1024] = {0};
        const char *pStart;
        char *pEnd;
        while (fgets(line, sizeof(line), fp))
        {
            if (!strstr(line, (const char *)"r-xp")) {
                continue;
            }
            pStart = strchr(line, '/');
            if (!pStart) {
                continue;
            }
            pEnd = (char *)strstr(line, libraryName);
            if (!pEnd) {
                continue;
            }
            /* 截取路径 */
            *(pEnd) = 0;
            snprintf(buff, buffSize, "%s", pStart);
            ret = 0;
            break;
        }
        fclose(fp);
    } while (0);
    /* 追加内容 */
    if (ret == 0 && appendString)
    {
        int32_t len = strlen(buff);
        snprintf(&buff[len], buffSize - len, "%s", appendString);
    }
    return ret;
}

int32_t ipcfork_checkProcess(int32_t pid)
{
    char procParh[128] = {0};
    snprintf(procParh, sizeof(procParh), "/proc/%d", pid);
    return access(procParh, F_OK);
}
/* ---------- Linux end ---------- */
#endif
